package com.example.spring_seatreservation.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.spring_seatreservation.Bean.*;
import com.example.spring_seatreservation.Other.DynamicTaskService;
import com.example.spring_seatreservation.Other.SignedNumber;
import com.example.spring_seatreservation.excel.UserExcel;
import com.example.spring_seatreservation.excel.UserExcelListener;
import com.example.spring_seatreservation.mapper.PublicMapper;
import com.example.spring_seatreservation.mapper.UserMapper;
import lombok.SneakyThrows;
import org.apache.poi.util.StringUtil;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.*;


@RestController
@RequestMapping("/user")
public class UserController {

    private final DynamicTaskService dynamicTask;


    public UserController(DynamicTaskService dynamicTask) {
        this.dynamicTask = dynamicTask;
    }

    @Resource
    UserMapper userMapper;
    @Resource
    PublicMapper publicMapper;

    @PostMapping("/updUser")
    public Map<String, Object> updUser(@RequestBody MyUser user){
        LambdaUpdateWrapper lambdaUpdateWrapper = Wrappers.<MyUser>lambdaUpdate().eq(MyUser::getUid,user.getUid());
        userMapper.update(user,lambdaUpdateWrapper);
        return new R().ok().builder();
    }

    @PostMapping("/delUser")
    public Map<String, Object> delUser(@RequestBody MyUser user){
        LambdaQueryWrapper lambdaQueryWrapper = Wrappers.<MyUser>lambdaQuery().eq(MyUser::getUid,user.getUid());
        userMapper.delete(lambdaQueryWrapper);
        return new R().ok().builder();
    }


    /**
     * startTime,endTime,sid,rid,uid
     *
     * @param map
     */
    @PostMapping("/addReservation")
    public Map<String, Object> addReservation(@RequestBody Map<String, Object> map) {

        List<Map<String, Object>> curReservation = userMapper.getCurReservation(map.get("uid"), map.get("orderDate").toString());
        //当前用户已有预约
        if (curReservation.size() > 0) {
            return new R().bad().builder();
        }
        long startTime = ((long) map.get("startTime"));
        long endTime = ((long) map.get("endTime"));

        String finishTaskName = ReservationCode.FINISH
                + "-" + map.get("sid");
        String unSignedTaskName = ReservationCode.UNSIGNED
                + "-" + map.get("sid");
        //插入预约记录
        userMapper.addReservation(map);
        userMapper.updateSeat(SeatCode.BE_RESERVATION, map.get("sid"));
        int rid = Integer.parseInt(map.get("rid").toString());

        //预约开始超过30分钟将设置预约状态为违约未签到，
        //并释放座椅
        dynamicTask.add(new MyTask(unSignedTaskName,
                startTime + 30 * 60 * 1000L, () -> {
//            dynamicTask.stop(finishTaskName);
//            userMapper.updateReservation(ReservationCode.UNSIGNED, rid);
//            userMapper.updateSeat(SeatCode.CAN_USE, map.get("sid"));
            Map<String,Object> user  = userMapper.getRuleBreak(map.get("uid"));
            int ruleBreak = Integer.parseInt(user.get("rulebreak").toString());
            if (ruleBreak >= 5){
                long threeDate = LocalDate.now().plusDays(3).atStartOfDay().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
                userMapper.setUser(map.get("uid"),2,threeDate);
                dynamicTask.add(new MyTask("用户解冻" + map.get("uid").toString(),threeDate,() -> {
                    userMapper.setUser(map.get("uid"),1,0L);
                    userMapper.updRuleBreak(map.get("uid"),0);
                }));
            } else {
                userMapper.updRuleBreak(map.get("uid"),ruleBreak + 1);
            }
        }));

        //预约结束时自动恢复座位状态
        dynamicTask.add(new MyTask(finishTaskName, endTime, () -> {
            userMapper.updateReservation(ReservationCode.FINISH, rid);
            userMapper.updateSeat(SeatCode.CAN_USE, map.get("sid"));
        }));

        return new R().ok().builder();
    }


    /**
     * 通过rid签到
     * 预约开始的时间前后半小时内有效(暂离1小时内有效)
     *
     * @param map
     * @return
     */
    @PostMapping("/toSigned")
    public Map<String, Object> toSigned(@RequestBody Map<String, Object> map) {
        long number = new Long(map.get("number").toString());
        //获取预约记录
        Map<String, Object> reservation = userMapper.getReservationByRid(map.get("rid"));

        long currentTimeMillis = System.currentTimeMillis();
        Object state = reservation.get("state");
        //预约签到
        if (state.equals(ReservationCode.TIME_BEGAN)) {
            if (currentTimeMillis > ((long) reservation.get("startTime")) + 30 * 60 * 1000L
                    || currentTimeMillis < ((long) reservation.get("startTime")) - 30 * 60 * 1000L) {
                //不在前后半小时内
                return new R().bad().builder();
            }
//            boolean flag = number == SignedNumber.getSignedNumber(reservation);
//            if (flag) {
            userMapper.updateReservation(ReservationCode.SIGNED_BE_USE, reservation.get("rid"));
            userMapper.updateSeat(SeatCode.BE_USE, reservation.get("sid"));
            //预约签到成功，关闭签到倒计时任务
            dynamicTask.stop(ReservationCode.UNSIGNED + "-" + reservation.get("sid").toString());
//            }
            return new R().ok().add("verify", true).builder();

        }
        //暂离签到
        else if (state.equals(ReservationCode.LEAVE)) {
            if (currentTimeMillis > ((long) reservation.get("leaveTime")) + 60 * 60 * 1000L) {
                //暂离超过1小时
                return new R().bad().builder();
            }
            boolean flag = number == SignedNumber.getLeaveSignedNumber(reservation);
            if (flag) {
                userMapper.updateReservation(ReservationCode.SIGNED_BE_USE, reservation.get("rid"));
                userMapper.updateSeat(SeatCode.BE_USE, reservation.get("sid"));
                //暂离回来签到成功，关闭签到倒计时任务
                dynamicTask.stop(ReservationCode.LEAVE_UNSIGNED + "-" + reservation.get("sid").toString());
            }
            return new R().ok().add("verify", flag).builder();
        } else {
            return new R().bad().builder();
        }
    }

    @PostMapping("/libSigned")
    public Map<String, Object> libSigned(@RequestBody Map<String, Object> map) {
        MyUser user = userMapper.getUserByNumberPass(map.get("number").toString(), map.get("password").toString());
        if (user == null) {
            return new R().bad("用户名密码错误").builder();
        }
        Map<String, Object> rec = userMapper.getReservationByUser(user.getUid(), map.get("recDate").toString(), map.get("sid"));
        if (rec == null) {
            return new R().bad("当日没有预约").builder();
        }
        if (!("0").equals(rec.get("state").toString())) {
            return new R().bad("当日已签到").builder();
        }
        userMapper.updateReservation(ReservationCode.SIGNED_BE_USE, rec.get("rid"));
        return new R().ok().builder();
    }

    /**
     * 暂离,rid,sid
     *
     * @param map
     * @return
     */
    @PostMapping("/toLeave")
    public Map<String, Object> toLeave(@RequestBody Map<String, Object> map) {
        long leaveTime = System.currentTimeMillis();
        //更新数据库中预约状态和座位状态
        userMapper.leaveReservation(leaveTime, map.get("rid"));
        userMapper.leaveSeat(map.get("sid"));
        //超过60分钟未签到将设置状态为暂离超时未签到，同时释放座位
        dynamicTask.add(new MyTask(ReservationCode.LEAVE_UNSIGNED + "-" + map.get("sid"),
                leaveTime + 60 * 60 * 1000L, () -> {
            dynamicTask.stop(ReservationCode.FINISH + "-" + map.get("sid").toString());
            userMapper.updateReservation(ReservationCode.LEAVE_UNSIGNED, map.get("rid"));
            userMapper.updateSeat(SeatCode.CAN_USE, map.get("sid"));
        }));
        return new R().builder();
    }

    @PostMapping("/signOut")
    public Map<String, Object> signOut(@RequestBody Map<String, Object> map) {
        userMapper.updateReservation(ReservationCode.FINISH, map.get("rid"));
        return new R().ok().builder();
    }

//    /**
//     * 获取当前其他用户的预约，得到自己可以预约的时间范围
//     * curTime,sid,
//     * @param map
//     * @return
//     */
//    @PostMapping("/getTimeRange")
//    public Map<String, Object> getTimeRange(@RequestBody Map<String, Object> map) {
//        List<Map<String, Object>> list = userMapper.getTimeRange(map);
//        return new R().ok().add("rows", ).builder();
//    }


    @PostMapping("/getReservation")
    public Map<String, Object> getReservationNeedSub(@RequestBody Map<String, Object> map) {
        return new R().ok().add("rows", userMapper.getReservation(map)).builder();
    }

    @PostMapping("/getReservationByUid")
    public Map<String, Object> getReservationByUid(@RequestBody Map<String, Object> map) {
        List<Map<String, Object>> list = userMapper.getReservationByUidNew(map.get("uid"));
        return new R().add("rows", list).builder();
    }

    @PostMapping("/getSeatReservation")
    public Map<String, Object> getSeatReservation(@RequestBody Map<String, Object> map) {
        List<Map<String, Object>> list = userMapper.getSeatReservation(map.get("number").toString(),map.get("userName").toString());
        return new R().add("rows", list).builder();
    }


    @PostMapping("/getScore")
    public Map<String, Object> getScore(@RequestBody Map<String, Object> map) {
        return new R().add("score", userMapper.getScore(map.get("uid"))).builder();
    }

    /**
     * 导入用户
     */
    @PostMapping("import-user")
    public Map<String, Object> importUser(MultipartFile file){
        String filename = file.getOriginalFilename();
        if (StringUtils.isBlank(filename)) {
            throw new RuntimeException("请上传文件!");
        }
        if ((!StringUtil.endsWithIgnoreCase(filename, ".xls") && !StringUtil.endsWithIgnoreCase(filename, ".xlsx"))) {
            throw new RuntimeException("请上传正确的excel文件!");
        }

        UserExcelListener importListener = new UserExcelListener(userMapper);
        try {
            EasyExcel.read(file.getInputStream(), UserExcel.class,importListener).sheet().doRead();
        } catch (Exception e) {
            return new R().bad(e.getMessage()).builder();
//            throw new RuntimeException(e.getMessage());
        }
        return new R().ok().builder();
    }

    /**
     * 导出模板
     */
    @SneakyThrows
    @GetMapping("export-template")
    public void exportUserTemplate(HttpServletResponse response) {
        List<UserExcel> list = new ArrayList<>();
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        String fileName = URLEncoder.encode("用户数据模板",StandardCharsets.UTF_8.toString());
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), UserExcel.class).sheet("用户数据表").doWrite(list);
    }

    /**
     * 导出用户
     */
    @SneakyThrows
    @GetMapping("export-user")
    public void exportUser(HttpServletResponse response) {
        List<MyUser> list = userMapper.selectList(null);
        List<UserExcel> exportList = new ArrayList<>();
        List<String> sex = Arrays.asList("女","男");
        List<String> type = Arrays.asList("学生","老师","管理员");
        for (MyUser user : list) {
            UserExcel userExcel = new UserExcel();
            userExcel.setNumber(user.getNumber());
            userExcel.setBirth(user.getBirth());
            userExcel.setUsername(user.getUsername());
            userExcel.setPhone(user.getPhone());
            userExcel.setEmail(user.getEmail());
            if (!Objects.isNull(user.getSex())) {
                userExcel.setSex(sex.get(user.getSex()));
            }
            if (!Objects.isNull(user.getType())) {
                userExcel.setType(type.get(user.getType()));
            }
            exportList.add(userExcel);
        }
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        String fileName = URLEncoder.encode("用户数据导出", StandardCharsets.UTF_8.toString());
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), UserExcel.class).sheet("用户数据表").doWrite(exportList);
    }
//
//    @PostMapping("/getReservationToSigned")
//    public Map<String, Object> getReservationToSigned(@RequestBody Map<String, Object> map) {
//        ListMap<String, Object> result = userMapper.getReservationToSigned(map.get("uid"));
//        return new R().add("score", ).builder();
//    }


}
